﻿using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls.Primitives;
using Redbrick.Silverlight.Common;

namespace Redbrick.Silverlight.Controls
{
	public class Resizeable 
	{

		#region Consts & Settings

		const string ResizeableStyleKey = "ResizeThumb";
		private static ResourceDictionary cachedResources;

		#endregion Consts & Settings

		#region Declarations

		private static Dictionary<FrameworkElement, Popup> _popups = new Dictionary<FrameworkElement, Popup>();
		public static readonly DependencyProperty IsResizeableProperty = DependencyProperty.RegisterAttached("IsResizeable", typeof(bool), typeof(Resizeable), new PropertyMetadata(false, OnIsResizeableedPropertyChanged));

		#endregion Declarations

		#region Constructor

		static  Resizeable()		
		{
			if (cachedResources == null)
				cachedResources = new ResourceDictionary()
				{
					Source = new Uri("/Redbrick.Silverlight;component/Resources/Styles.xaml", UriKind.Relative),
				};
		}

		#endregion Constructor

		#region Methods

		public static bool GetIsResizeable(DependencyObject obj)
		{
			return (bool)obj.GetValue(IsResizeableProperty);
		}

		public static void SetIsResizeable(DependencyObject obj, bool value)
		{
			obj.SetValue(IsResizeableProperty, value);
		}

		public static Point GetRelativePosition(UIElement element, UIElement otherElement)
		{
			return element.TransformToVisual(otherElement)
							 .Transform(new Point(0, 0));
		}

		#endregion Methods

		#region Events

		private static void OnIsResizeableedPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
		{


			FrameworkElement element = d as FrameworkElement;
			if (d != null)
			{
				// Create a popup.
				Popup popup = new Popup();
				
				// and associate it with the element that can be re-sized
				_popups[element] = popup;

							
				// Add a thumb to the pop-up
				Thumb thumb = new Thumb()
				{
					Style = cachedResources[ResizeableStyleKey] as Style
				};
				
				popup.Child = thumb;

				// add a relationship from the thumb to the target
				thumb.Tag = element;

				popup.IsOpen = true;

				thumb.DragDelta += new DragDeltaEventHandler(Thumb_DragDelta);
				element.SizeChanged += new SizeChangedEventHandler(Element_SizeChanged);
			}
		}

		/// <summary>
		/// Handles drag events from the thumb, resizing the associated element
		/// </summary>
		private static void Thumb_DragDelta(object sender, DragDeltaEventArgs e)
		{
			Thumb thumb = sender as Thumb;
			FrameworkElement fe = thumb.Tag as FrameworkElement;

			// set the Width / Height of the element
			if (fe.Width == 0.0 || double.IsNaN(fe.Width))
			{
				fe.Width = fe.ActualWidth;
			}
			if (fe.Height == 0.0 || double.IsNaN(fe.Height))
			{
				fe.Height = fe.ActualHeight;
			}

			// apply the drag deltas
			double newWidth = fe.Width + e.HorizontalChange;
		
			newWidth = Math.Max(0, newWidth);
			if (newWidth.InclusiveBetween(fe.MinWidth, fe.MaxWidth))
				fe.Width = newWidth;

			double newHeight = fe.Height + e.VerticalChange;
			newHeight = Math.Max(0, newHeight);

			if (fe.Height.InclusiveBetween(fe.MinHeight, fe.MaxHeight))
				fe.Height = newHeight;
		}

		/// <summary>
		/// Handle size changes repositioning the thumb / popup
		/// </summary>
		private static void Element_SizeChanged(object sender, SizeChangedEventArgs e)
		{
			FrameworkElement element = sender as FrameworkElement;

			// find the popup that hosts the thumb
			Popup popup = _popups[element];

			// reposition the popup
			FrameworkElement root = Application.Current.RootVisual as FrameworkElement;
			Point elementLocation = GetRelativePosition(element, root);

			var childElement = popup.Child as FrameworkElement;

			// Set where the popup will show up on the screen.
			popup.VerticalOffset = elementLocation.Y + element.ActualHeight - childElement.ActualHeight;
			popup.HorizontalOffset = elementLocation.X + element.ActualWidth - childElement.ActualWidth;

		}

		#endregion Events
	}
}
